package cn.yto.print.plugins;

import cn.yto.print.config.CaffeineCacheConfig;
import cn.yto.print.config.i18n.I18nResourceManager;
import cn.yto.print.controller.IndexController;
import cn.yto.print.enums.MessageTypeEnum;
import cn.yto.print.enums.PluginRegistryEnum;
import cn.yto.print.listener.PluginProcessMonitor;
import cn.yto.print.listener.ProcessListener;
import cn.yto.print.system.SpringContextHolder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;

import java.lang.reflect.Method;

public class PluginMonitorRunnable implements Runnable {

    private static final Logger logger = LogManager.getLogger(PluginMonitorRunnable.class);

    @Override
    public void run() {
        // 获取所有插件注册枚举
        PluginRegistryEnum[] pluginEnums = PluginRegistryEnum.values();
        if (pluginEnums.length == 0) {
            logger.warn("未检测到任何插件注册信息，插件进程监控将不会执行。");
            return;
        }

        for (PluginRegistryEnum registryEnumInstance : pluginEnums) {
            String processesForCurrentPlugin = registryEnumInstance.getProcesses();
            ProcessListener listener = new ProcessListener() {
                @Override
                public void onProcessStarted(String processName) {
                    handlePluginStartup(registryEnumInstance);
                }

                @Override
                public void onProcessStopped(String processName) {
                    handlePluginShutdown(registryEnumInstance);
                }
            };
            PluginProcessMonitor.getInstance().addProcessListener(processesForCurrentPlugin, listener);
        }
    }

    private void handlePluginStartup(PluginRegistryEnum pluginRegistry) {
        String message = String.format(
                I18nResourceManager.getInstance().get("index.console.plugin"),
                I18nResourceManager.getInstance().get(pluginRegistry.getLocale())
        );
        logger.info("【{}】打印组件已启动，小助手开始准备连接", pluginRegistry.getName());
        SpringContextHolder.getBean(IndexController.class).addConsoleLog(message, MessageTypeEnum.INFO);
        try {
            Thread.sleep(1000);
            refreshSingletonBean(pluginRegistry.getBeanClass());
        } catch (Exception e) {
            logger.error("连接【{}】打印组件时发生异常", pluginRegistry.getName(), e);
        } finally {
            CaffeineCacheConfig.getProcessCache().invalidate(pluginRegistry.getCode());
        }
    }

    private void handlePluginShutdown(PluginRegistryEnum pluginRegistry) {
        logger.info("【{}】打印组件已经关闭，连接断开", pluginRegistry.getName());
        CaffeineCacheConfig.getProcessCache().invalidate(pluginRegistry.getCode());
    }

    public void refreshSingletonBean(Class<?> beanClass) throws Exception {
        ConfigurableApplicationContext applicationContext =
                (ConfigurableApplicationContext) SpringContextHolder.getApplicationContext();
        DefaultListableBeanFactory beanFactory =
                (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        // 获取指定类型的 Bean 名称
        String[] beanNames = applicationContext.getBeanNamesForType(beanClass);
        if (beanNames.length != 1) {
            throw new RuntimeException("Spring beanClass [" + beanClass + "] have multiple instances");
        }
        String targetBeanName = beanNames[0];
        if (beanFactory.containsSingleton(targetBeanName)) {
            beanFactory.destroySingleton(targetBeanName);
        }
        Object newBeanInstance = beanFactory.createBean(beanClass);
        beanFactory.autowireBean(newBeanInstance);
        // 初始化
        beanFactory.initializeBean(newBeanInstance, targetBeanName);
        Method initMethod = beanClass.getMethod("initialize");
        initMethod.invoke(newBeanInstance);
        beanFactory.registerSingleton(targetBeanName, newBeanInstance);
    }

}

